package net.cyl.util;


import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * Json 工具类，用于对象和 JSON 字符串、字节数组之间的相互转换
 */
@Slf4j
public class JsonUtil {
    private static final ObjectMapper mapper = new ObjectMapper();

    static {
        // 设置可用单引号
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        // 序列化的时候序列对象的所有属性
        mapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.ALWAYS);
        // 反序列化的时候如果多了其他属性,不抛出异常
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 如果是空对象的时候,不抛异常
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 取消时间的转化格式,默认是时间戳,可以取消,同时需要设置要表现的时间格式
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        // 处理 Java 8 日期时间类型
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        mapper.registerModule(javaTimeModule);

        // 解决 Long 类型转 JSON 精度丢失问题
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        mapper.registerModule(simpleModule);
    }

    /**
     * 对象转为 Json 字符串
     *
     * @param obj 待转换的对象
     * @return 转换后的 Json 字符串，转换失败返回 null
     */
    public static String obj2Json(Object obj) {
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.error("对象转为 Json 字符串失败", e);
            return null;
        }
    }

    /**
     * json 字符串转为对象
     *
     * @param jsonStr  Json 字符串
     * @param beanType 目标对象的类型
     * @param <T>      泛型类型
     * @return 转换后的对象，转换失败返回 null
     */
    public static <T> T json2Obj(String jsonStr, Class<T> beanType) {
        try {
            return mapper.readValue(jsonStr, beanType);
        } catch (Exception e) {
            log.error("Json 字符串转为对象失败", e);
            return null;
        }
    }

    /**
     * json 数据转换成 pojo 对象 list
     *
     * @param jsonData Json 数据
     * @param beanType 列表中对象的类型
     * @param <T>      泛型类型
     * @return 转换后的列表，转换失败返回 null
     */
    public static <T> List<T> json2List(String jsonData, Class<T> beanType) {
        JavaType javaType = mapper.getTypeFactory().constructParametricType(ArrayList.class, beanType);
        try {
            return mapper.readValue(jsonData, javaType);
        } catch (Exception e) {
             log.error("Json 数据转换成 pojo 对象 list 失败", e);
            return null;
        }
    }

    /**
     * 对象转为 byte 数组
     *
     * @param obj 待转换的对象
     * @return 转换后的字节数组，转换失败返回 null
     */
    public static byte[] obj2Bytes(Object obj) {
        try {
            return mapper.writeValueAsBytes(obj);
        } catch (JsonProcessingException e) {
            log.error("对象转为 byte 数组失败", e);
            return null;
        }
    }

    /**
     * byte 数组转为对象
     *
     * @param byteArr 字节数组
     * @param beanType 目标对象的类型
     * @param <T>      泛型类型
     * @return 转换后的对象，转换失败返回 null
     */
    public static <T> T bytes2Obj(byte[] byteArr, Class<T> beanType) {
        try {
            return mapper.readValue(byteArr, beanType);
        } catch (Exception e) {
            log.error("byte 数组转为对象失败", e);
            return null;
        }
    }
}